//
// Created by yonghu0 on 25-11-14.
//

#ifndef LOGGER_H
#define LOGGER_H

#include <string>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <thread>
#include <iostream>

#define LOG_INFO(fmt, ...) Logger::GetInstance().AddToQueue("INFO", __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__)
#define LOG_WARNING(fmt, ...) Logger::GetInstance().AddToQueue("WARNING", __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__)
#define LOG_ERROR(fmt, ...) Logger::GetInstance().AddToQueue("ERROR", __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__)
#define LOG_FATAL(fmt, ...) Logger::GetInstance().AddToQueue("FATAL", __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__)

template<typename T>
class LockQueue
{
public:
    void push(const T &data)
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        m_queue.push(data);
        m_cv.notify_one();
    }

    T pop()
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        while (m_queue.empty())
        {
            m_cv.wait(lock);
        }
        T data = m_queue.front();
        m_queue.pop();
        return data;
    }

private:
    std::mutex m_mutex;
    std::condition_variable m_cv;
    std::queue<T> m_queue;
};

class Logger
{
public:
    static Logger &GetInstance();
    // 结尾必须有/，例如：./log/
    void SetFileDir(const std::string &file_dir);
    void AddToQueue(const char *level, const char *file, int line, const char *func, const std::string &format, ...);

private:
    std::string m_file_dir;
    LockQueue<std::string> m_log_queue;

    Logger();
    ~Logger();

    Logger(const Logger &) = delete;
    Logger(Logger &&) = delete;
    Logger &operator=(const Logger &) = delete;
    Logger &operator=(Logger &&) = delete;

    void Start();
    void WriteLog();
};


#endif //LOGGER_H
